package pt.isel.pdm.ouryamba;

import java.util.List;

import winterwell.jtwitter.Twitter.Status;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.widget.RemoteViews;

public class Widget extends AppWidgetProvider
{
	/**
	 * Is the collection of statuses that are accessed by all widgets.
	 * */
	private static Info[] values;
	/**
	 * Is the pointer for one status from the collection of statuses.
	 * */
	private static int msgOffset;
	private General app;
	private Intent timelineIntent;
	private enum Action
	{
		next,
		previous,
		refresh
	}

	/**
	 * Construct the pending intent with the parameters.
	 * 
	 * @param context Is the context from where this intent is sent.
	 * @param action Is the type of action this intent should transport.
	 * @return The constructed pending intent.
	 * */
	private PendingIntent getPendingIntent(Context context, Action action) 
	{
		Intent intent = new Intent(context, Widget.class);
		intent.setAction(action.toString());
		return PendingIntent.getBroadcast(context, 0, intent, 0);  
	}
	
	/**
	 * Indicate the actions to take when an update intent is received by the widget.</br>
	 * 
	 * For each widget on the home screen, construct three different pending intents, one for
	 * each button, and set them as the intents to broadcast on each click.
	 * 
	 * @see #getPendingIntent(Context, Action)
	 * @see #refreshAction(Context, AppWidgetManager, int[])
	 * */
	@Override
	public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] widgetIds) 
	{	
		ComponentName widgetInstance;
		RemoteViews remoteViews;
		for(int i =  0; i < widgetIds.length; i++)
		{
			widgetInstance = new ComponentName(context, Widget.class);
			remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
			remoteViews.setOnClickPendingIntent(R.id.idWidgetButtonPrevious, getPendingIntent(context, Action.previous));
			remoteViews.setOnClickPendingIntent(R.id.idWidgetButtonRefresh, getPendingIntent(context, Action.refresh));
			remoteViews.setOnClickPendingIntent(R.id.idWidgetButtonNext, getPendingIntent(context, Action.next));			
			appWidgetManager.updateAppWidget(widgetInstance, remoteViews);
		}
		refreshAction(context, appWidgetManager, widgetIds);
	}

	/**
	 * Analysis the intent received and perform the appropriate code.
	 * 
	 * @see #previousAction(Context, AppWidgetManager, int[])
	 * @see #nextAction(Context, AppWidgetManager, int[])
	 * @see #refreshAction(Context, AppWidgetManager, int[])
	 * */
	@Override
	public void onReceive(Context context, Intent intent) 
	{
		if(app == null)
		{
			app = (General) context.getApplicationContext();
		}
		AppWidgetManager mgr = AppWidgetManager.getInstance(context);
		ComponentName cn = new ComponentName(context, Widget.class);
		if(intent.getAction().equals(Action.previous.name()))
		{
			previousAction(context, mgr, mgr.getAppWidgetIds(cn));
		}
		else if(intent.getAction().equals(Action.next.name()))
		{
			nextAction(context, mgr, mgr.getAppWidgetIds(cn));
		}
		else if(intent.getAction().equals(Action.refresh.name()))
		{
			refreshAction(context, mgr, mgr.getAppWidgetIds(cn));
		}
		super.onReceive(context, intent);
	}
	
	/**
	 * Decrement a pointer position in the list of statuses.
	 * 
	 * @see #reshowAction(Context, AppWidgetManager, int[])
	 * */
	private void previousAction(Context context, AppWidgetManager appWidgetManager, int[] widgetIds)
	{
		if(msgOffset > 0)
		{
			msgOffset--;
			reshowAction(context, appWidgetManager, widgetIds);
		}
	}
	
	/**
	 * Increment a pointer position in the list of statuses.
	 * 
	 * @see #reshowAction(Context, AppWidgetManager, int[])
	 * */
	private void nextAction(Context context, AppWidgetManager appWidgetManager, int[] widgetIds)
	{
		if(values != null && msgOffset < values.length - 1)
		{
			msgOffset++;
			reshowAction(context, appWidgetManager, widgetIds);
		}
	}
	
	/**
	 * Update the list of status by sending an intent to the TimelinePullService.
	 * 
	 * @see General#dbSelectByCommittedValue(boolean)
	 * @see #reshowAction(Context, AppWidgetManager, int[])
	 * @see General#log(String)
	 * @see General#logException(Exception)
	 * */
	private void refreshAction(final Context context, final AppWidgetManager appWidgetManager, final int[] widgetIds)
	{
		if(timelineIntent == null)
		{
			timelineIntent = new Intent(context, TimelinePullService.class);
		}
		context.startService(timelineIntent);
		app.waiter.Wait(null, new Runnable()
		{
			@Override
			public void run() 
			{
				List<Status> list = app.dbSelectByCommittedValue(true);
				try
				{
					int length = list.size(), index = 0;
					if(length > 0)
					{
						Info[] dummyArray = new Info[length];
						for(Status status : list)
						{
							dummyArray[index++] = new Info(status.user.screenName, status.text);
						}
						list = null;
						values = dummyArray;
						msgOffset = 0;
						reshowAction(context, appWidgetManager, widgetIds);
					}
				}
				catch (Exception e)
				{
					app.log("Widget.refreshAction(): Exception thrown.");
					app.logException(e);
					return;
				}
			}
		});
	}	
	
	/**
	 * Update the text views of all widgets with the information of the status that is pointed on the list. 
	 * */
	private synchronized void reshowAction(Context context, AppWidgetManager appWidgetManager, int[] widgetIds)
	{
		RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
		if(values != null && values != null && msgOffset < values.length)
		{
			remoteViews.setTextViewText(R.id.idWidgetAuthorTextView, values[msgOffset].user);
			remoteViews.setTextViewText(R.id.idWidgetMsgTextView, values[msgOffset].status);
		}
		for(int id : widgetIds) 
		{
			appWidgetManager.updateAppWidget(id, remoteViews);
		}
	}
	
	/**
	 * Is the class the represent one status.
	 * */
	private class Info
	{
		public final String user;
		public final String status;
		
		public Info(String user, String status)
		{
			this.user = user;
			this.status = status;
		}
	}
}
